// 原型实现
function Stack() {
  this.items = [];
}
Stack.prototype = {
  // 添加一个活多个到栈顶
  push: function(element) {
    this.items.push(element);
  },
  // 移除栈顶元素，并返回移除的元素
  pop: function() {
    return this.items.pop();
  },
  // 返回栈顶元素
  peek: function() {
    let len = this.items.length;
    return this.items[len - 1];
  },
  // 栈是否有元素
  isEmpty: function() {
    return this.items.length === 0;
  },
  // 清空栈顶
  clear: function() {
    this.items = [];
  },
  // 返回栈顶的大小
  size: function() {
    return this.items.length
  },
  // 输出
  print: function() {
    console.log(this.items.toString())
  }
}

// 使用ES6实现栈，
// 这种方法不能再类中声明变量，只能在construtor 里申明变量
// 问题是items 是公用的，他是基于原型的，
// 是不能够声明私有属性的或者方法的，我们希望只暴露给用户类的方法
class Stack2 {
  constructor() {
    this.items = [];
  }
  push() {};
  pop() {};
  //其他方法
}

// ES6创建栈实现 私有属性

let _items = Symbol(); //声明symbol 变量
class Stack3 {
  constructor() {
    this[_items] = [];
  }
  // 其他方法
}
// 这种方法创建了假的私有属性，因为ES6新增的 Object.getOwnPropertySymbols方法能够取到类里面声明的所 有Symbols属性
let objectSymbols = Object.getOwnPropertySymbols(stack);
console.log(objectSymbols.length); // 1 
console.log(objectSymbols); // [Symbol()] 
console.log(objectSymbols[0]); // Symbol() 
stack[objectSymbols[0]].push(1);

// 访问stack[objectSymbols[0]]是可以得 到_items的。并且，_items属性是一个数组，可以进行任意的数 组操作，比如从中间删除或添加元素。
// 我们操作的是栈，不应该出 现这种行为。

/* 
使用ES6 的WeakMap 实现栈
有一种数据类型可以确保属性是私有的，这就是WeakMap。
**/

// 声明一个WeakMap类型的变量items。
const items = new WeakMap();

class Satck4 {
  constructor() {
    // 在constructor中，以this（Stack类自己的引用） 为键，把代表栈的数组存入items。
    items.set(this, []);
  }
  push(element) {
    // 从WeakMap中取出值，即以this为键,从items中取值。
    let s = items.get(this); //{3} 
    s.push(element);
  }
  pop() {
    let s = items.get(this);
    let r = s.pop();
    return r;
  }
  //其他方法
}

/* 但是,items现在仍然是在Stack类以外声明的,因此谁都 可以改动它。
我们要用一个闭包（外层函数）把Stack类包起来， 这样就只能在这个函数里访问WeakMap：
 */

let Satck4_1 = (function() {
  // 声明一个WeakMap类型的变量items。
  const items = new WeakMap();
  class Satck5 {
    constructor() {
      // 在constructor中，以this（Stack类自己的引用） 为键，把代表栈的数组存入items。
      items.set(this, []);
    }
    push(element) {
      // 从WeakMap中取出值，即以this为键,从items中取值。
      let s = items.get(this); //{3} 
      s.push(element);
    }
    pop() {
      let s = items.get(this);
      let r = s.pop();
      return r;
    }
    //其他方法
  }
  return Satck5
}())

// 然而，用这种方法的话，扩展类无法继承私 有属性。